#include "pwm_generator_config.h"
#include "./BSP/TIMER/gtim.h"
#include "./sys_param/sys_param.h"
#include <stdio.h>
#include <math.h>   /* 需要使用fabsf函数 */
#include <float.h>  /* 需要使用FLT_MAX */

/* TIM句柄外部声明 */
extern TIM_HandleTypeDef g_timx_pwm_chy_handle;

/**
 * @brief 使用遍历法计算最佳的PSC和ARR值
 * @param freq: 目标频率
 * @param p_psc: 指向存储最佳PSC值的变量
 * @param p_arr: 指向存储最佳ARR值的变量
 * @retval 实际输出频率
 * 
 * @note 频率计算公式: PWM频率 = 时钟频率 / ((PSC+1) * (ARR+1))
 *       其中，时钟频率 = 72MHz (STM32F103)
 *       算法通过遍历PSC值，计算最佳ARR值，寻找误差最小的参数组合
 */
static float Calculate_Optimal_PWM_Params(uint32_t freq, uint16_t *p_psc, uint16_t *p_arr)
{
    uint32_t clk = 72000000UL;  /* STM32F103的系统时钟 */
    uint16_t best_psc = 0;
    uint16_t best_arr = 0;
    float min_error = FLT_MAX;
    float actual_freq = 0;

    /* 限制频率范围，防止极端值 */
    if (freq < 1) freq = 1;
    
    /* 遍历可能的PSC值，寻找最佳组合 */
    for (uint32_t psc = 1; psc <= 65535; psc++) 
    {
        /* 计算理论上的ARR值(浮点数) */
        float exact_arr = ((float)clk / (psc + 1) / freq) - 1;
        /* exact_arr: 理论上的精确ARR值，通常是小数，无法直接用于硬件 */
        
        /* 如果ARR超出范围，跳过当前PSC */
        if (exact_arr > 65535 || exact_arr < 100)
            continue;
            
        /* 向下取整和向上取整的ARR值 */
        uint32_t arr_floor = (uint32_t)exact_arr;  /* 向下取整，可能导致实际频率略高于目标频率 */
        uint32_t arr_ceil = arr_floor + 1;         /* 向上取整，可能导致实际频率略低于目标频率 */
        
        /* 计算实际频率和误差(向下取整) */
        float actual_freq_floor = (float)clk / (psc + 1) / (arr_floor + 1);
        float error_floor = fabsf(actual_freq_floor - freq);
        
        /* 计算实际频率和误差(向上取整) */
        float actual_freq_ceil = (float)clk / (psc + 1) / (arr_ceil + 1);
        float error_ceil = fabsf(actual_freq_ceil - freq);
        
        /* 选择误差较小的方案 */
        uint32_t arr = (error_floor <= error_ceil) ? arr_floor : arr_ceil;
        float error = (error_floor <= error_ceil) ? error_floor : error_ceil;
        float curr_actual_freq = (error_floor <= error_ceil) ? actual_freq_floor : actual_freq_ceil;
        
        /* 更新最优解 */
        if (error < min_error) 
        {
            min_error = error;
            best_psc = psc;
            best_arr = arr;
            actual_freq = curr_actual_freq;
            
            /* 如果误差已经很小，可以提前退出 */
            if (error < 0.01)
                break;
        }
        
        /* 加速遍历策略：随着PSC增大，可以加大步长 */
        /* 说明：PSC值越大，相邻PSC值对应的频率变化越小，因此可以跳过部分值
         * 1. PSC从100变为101时，频率变化约为1%
         * 2. PSC从1000变为1001时，频率变化约为0.1%
         * 3. PSC从10000变为10001时，频率变化约为0.01%
         * 使用加速遍历可将循环次数从65535减少到约1800次，大幅提升效率，且几乎不损失精度
         */
        if (psc >= 10000) psc += 999;       /* 10000以上，步长为1000 */
        else if (psc >= 1000) psc += 99;    /* 1000-9999，步长为100 */
        else if (psc >= 100) psc += 9;      /* 100-999，步长为10 */
    }

    /* 返回找到的最佳参数 */
    *p_psc = best_psc;
    *p_arr = best_arr;
    
    /* 打印调试信息 */
    printf("Target: %lu Hz, Optimal PWM: PSC=%u, ARR=%u, Actual=%.3f Hz, Error=%.3f Hz\n", 
           freq, best_psc, best_arr, actual_freq, fabsf(actual_freq - freq));
    
    return actual_freq;
}

/**
 * @brief 初始化PWM生成器
 * @retval 无
 */
void PWM_Generator_Init(void)
{
    /* 配置并启动PWM */
    float actual_freq = PWM_Generator_UpdateFrequency(g_tPWMParam.frequency);
    PWM_Generator_UpdateDutyCycle(g_tPWMParam.dutyCycle);
    
    /* 输出初始化信息 */
    printf("PWM generator initialized with %dHz (actual: %.2fHz), %d%% duty cycle\r\n", 
           g_tPWMParam.frequency, actual_freq, g_tPWMParam.dutyCycle);
}

/**
 * @brief 停止PWM生成器
 * @retval 无
 */
void PWM_Generator_DeInit(void)
{
    /* 停止PWM输出 */
    HAL_TIM_PWM_Stop(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY);
    
    /* 输出反初始化信息 */
    printf("PWM generator stopped\r\n");
}

/**
 * @brief 更新PWM频率
 * @param frequency: 频率值（1-10000Hz）
 * @retval 实际输出频率值
 * 
 * @note 频率计算公式: PWM频率 = 时钟频率 / ((PSC+1) * (ARR+1))
 *       本函数使用遍历法自动寻找最佳PSC和ARR组合，以最小化频率误差
 *       同时会保持占空比不变，通过重新计算CCR值实现
 */
float PWM_Generator_UpdateFrequency(uint16_t frequency)
{
    /* 限制频率范围 */
    if (frequency < 1) frequency = 1;
    if (frequency > 10000) frequency = 10000;
    
    /* 更新参数系统中的频率值 */
    g_tPWMParam.frequency = frequency;
    
    /* 使用遍历法计算最佳PSC和ARR值 */
    uint16_t psc, arr;
    float actual_freq = Calculate_Optimal_PWM_Params(frequency, &psc, &arr);
    
    /* 停止PWM */
    HAL_TIM_PWM_Stop(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY);
    
    /* 配置新的频率 */
    g_timx_pwm_chy_handle.Instance = GTIM_TIMX_PWM;
    g_timx_pwm_chy_handle.Init.Prescaler = psc;
    g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    g_timx_pwm_chy_handle.Init.Period = arr;
    HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);
    
    /* 计算新的比较值来保持相同的占空比 */
    uint16_t pulse = (uint16_t)((arr + 1) * g_tPWMParam.dutyCycle / 100) - 1;
    if (pulse < 1) pulse = 1;
    if (pulse > arr) pulse = arr;
    
    /* 配置新的比较值 */
    TIM_OC_InitTypeDef sConfigOC = {0};
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = pulse;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    
    HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &sConfigOC, GTIM_TIMX_PWM_CHY);
    
    /* 重新启动PWM */
    HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY);
    
    return actual_freq;
}

/**
 * @brief 更新PWM占空比
 * @param dutyCycle: 占空比值（1-99%）
 * @retval 无
 * 
 * @note 占空比计算公式: 占空比 = (CCR值 + 1) / (ARR值 + 1) × 100%
 *       反向应用: CCR值 = ((ARR值 + 1) × 占空比 / 100) - 1
 *       其中，占空比范围限制在1-99%，避免完全的高电平或低电平状态
 */
void PWM_Generator_UpdateDutyCycle(uint8_t dutyCycle)
{
    /* 限制占空比范围 */
    if (dutyCycle > 100) dutyCycle = 100;
    
    /* 更新参数系统中的占空比值 */
    g_tPWMParam.dutyCycle = dutyCycle;
    
    /* 计算比较值 */
    uint16_t arr = g_timx_pwm_chy_handle.Init.Period;
    /* 根据占空比公式反向计算CCR值：CCR = ((ARR+1) * 占空比 / 100) - 1 
     * 例如：50%占空比，ARR=999，则CCR = ((999+1) * 50 / 100) - 1 = 499
     * 此时高电平时间与低电平时间相等，各占50%
     */
    uint16_t pulse = (uint16_t)((arr + 1) * dutyCycle / 100) - 1;
    
    /* 限制CCR值范围，确保有效的PWM输出 */
    if (pulse < 1) pulse = 1;         /* 避免CCR太小或为0，确保至少有最小的高电平时间 */
    if (pulse > arr) pulse = arr;     /* 避免CCR大于ARR，确保至少有最小的低电平时间 */
    
    /* 直接更新比较寄存器的值 */
    __HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY, pulse);
    
    printf("Duty cycle updated to %d%%, Pulse=%d\r\n", dutyCycle, pulse);
}

/**
 * @brief 保存PWM生成器配置到EEPROM
 * @retval 无
 */
void PWM_Generator_SaveConfig(void)
{
    /* 保存参数到EEPROM */
    SaveSingleParamByAddr(&g_tPWMParam.frequency);
    SaveSingleParamByAddr(&g_tPWMParam.dutyCycle);
}

/**
 * @brief 从EEPROM加载PWM生成器配置
 * @retval 无
 */
void PWM_Generator_LoadConfig(void)
{
    /* 从EEPROM加载参数 */
    LoadSingleParamByAddr(&g_tPWMParam.frequency);
    LoadSingleParamByAddr(&g_tPWMParam.dutyCycle);
    
    /* 应用加载的配置 */
    PWM_Generator_UpdateFrequency(g_tPWMParam.frequency);
    PWM_Generator_UpdateDutyCycle(g_tPWMParam.dutyCycle);
} 
